//
// Created by 邹嘉旭 on 2025/8/7.
//

#include "gsg.h"

#include <ipv6_parse.h>

#include "as_entity.h"
#include "define.h"



static l_err init_gsg_as_entities(net_element_t *net_ele) {
    for (int i = 0; i < 40; i++) {
        as_entity_t *as = init_as_entity(1012345 + i * 10000, 301 + i, 16, ELEMENT_GSG, net_ele);

        // 直接变为connected状态
        if (in_state(&as->gsg_sm, "GSG_INITIAL")) {
            if (change_state(&as->gsg_sm, EV_DEFAULT,
                             &(fsm_event_data_t){
                                 &gsg_fsm_events[GSG_SAC_ALLOCING], NULL
                             }) != LD_OK) {
                cn_log_error( net_ele->element_tag, INTERFACE_G1, "cant change state correctly");
                return LD_ERR_INVALID;
            }

            if (change_state(&as->gsg_sm, EV_DEFAULT,
                             &(fsm_event_data_t){
                                 &gsg_fsm_events[GSG_CONNECTED], NULL
                             }) != LD_OK) {
                cn_log_error( net_ele->element_tag, INTERFACE_G1, "cant change state correctly");
                return LD_ERR_INVALID;
                             }
        }


        set_as_enode(net_ele->as_map, as);
    }

    // print_as_info(ELEMENT_GSG, net_ele->as_map, UA_TAG | SAC_TAG | CURRENT_PEER_TAG | NEXT_PEER_TAG | GS_IP_TAG | AS_IP_TAG | GS_PORT_TAG | STATUS_TAG);


    return LD_OK;
}


gsg_entity_t *init_gsg_entity() {
    gsg_entity_t *gsg_entity = malloc(sizeof(gsg_entity_t));

    return gsg_entity;
}

void free_gsg_entity(gsg_entity_t *entity) {
    free(entity);
}

/**
 * GSG 服务端业务（仅GS1接口）
 * @param bc
 * @return
 */
static l_err gsg_server_handler(basic_conn_t *bc) {
    if (!bc || !bc->read_pkt ) {
        log_error("GSG server recv failed");
        return LD_ERR_NULL;
    }
    element_propt_t *element_propt = (element_propt_t *) bc;

    net_ctx_t *ctx = bc->opt;
    meta_service_t *meta = ctx->arg;

    // cn_log_buf(LOG_INFO, meta->net_ele->element_tag, meta->interface_type, "RECV GSG", element_propt->bc.read_pkt->ptr,
    //            element_propt->bc.read_pkt->len);
    uint8_t type = (*element_propt->bc.read_pkt->ptr >> (BITS_PER_BYTE - GS1_TYP_LEN)) & (0xFF >> (BITS_PER_BYTE - GS1_TYP_LEN));
    if (type > GS1_TYPE_MAX) {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "GSG Type out of range");
        return LD_ERR_INVALID;
    }
    cn_format_desc_t *desc = &gs1_format_descs[type];
    if (desc->type == 0 || type > gs1_format_count) {
        cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Wrong Message Type");
        return LD_ERR_INVALID;
    }

    if (desc->recv_handler) {
        if (desc->recv_handler(meta->net_ele, desc, element_propt->bc.read_pkt, element_propt) != LD_OK) {
            cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Handle Message Failed!");
            return LD_ERR_INVALID;
        }
    }

    return LD_OK;
}

/**
 * GSG 客户端业务（G1接口）)
 * @param bc
 * @return
 */
static l_err gsg_client_handler(basic_conn_t *bc) {
    if (!bc || !bc->read_pkt ) {
        log_error("GSG client recv failed");
        return LD_ERR_NULL;
    }
    element_propt_t *element_propt = (element_propt_t *) bc;

    net_ctx_t *ctx = bc->opt;
    meta_service_t *meta = ctx->arg;
    net_element_t *net_ele = meta->net_ele;

    switch (meta->interface_type) {
        case INTERFACE_G1: {
            uint8_t type = *element_propt->bc.read_pkt->ptr ;

            cn_format_desc_t *recv_desc = get_non_sequential_desc(g1_format_size, g1_format_descs, type);
            if (!recv_desc) {
                cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No desc");
                return LD_ERR_NULL;
            }

            if (recv_desc->recv_handler) {
                if (recv_desc->recv_handler(meta->net_ele, recv_desc, element_propt->bc.read_pkt, element_propt) != LD_OK) {
                    cn_log_error(meta->net_ele->element_tag, meta->interface_type, "Handle Message Failed!");
                    return LD_ERR_INVALID;
                }
            } else {
                cn_log_error(meta->net_ele->element_tag, meta->interface_type, "No handler");
                return LD_ERR_INVALID;
            }
            break;
        }
        case INTERFACE_G1U: {

            ipv6_tcp_t *tcp_pkt = calloc(1, sizeof(ipv6_tcp_t));
            PARSE_DSTR_PKT(element_propt->bc.read_pkt, tcp_pkt, data, ipv6_tcp_desc, 60, 0 );

            as_entity_t *as = get_as_senode_by_as_IP(net_ele->as_map, (char *)tcp_pkt->dst_address->ptr);
            if (!as) {
                cn_log_error(net_ele->element_tag, INTERFACE_G1U, "No AS found");
                free_ipv6_tcp(tcp_pkt);
                return LD_ERR_INVALID;
            }

            gs1_data_t gs1_data = {
                .VER = GS1_DATA_UP,
                .AS_SAC = as->SAC,
                .IDTF = 1,
                .sdu = init_buffer_unptr(),
            };

            CLONE_TO_CHUNK(*gs1_data.sdu, element_propt->bc.read_pkt->ptr, element_propt->bc.read_pkt->len);

            cn_format_desc_t *send_desc = &gs1_format_descs[GS1_DATA_UP];
            if (!send_desc || !send_desc->send_handler || send_desc->send_handler(
                    net_ele,
                    &gs1_data,
                    send_desc,
                    get_propt(net_ele, INTERFACE_GS1, 0),
                    INTERFACE_GS1
                ) != LD_OK) {
                cn_log_error(net_ele->element_tag, INTERFACE_GS1, "Failed to send");
                free_ipv6_tcp(tcp_pkt);
                free_buffer(gs1_data.sdu);
                return LD_ERR_NULL;
            }

            free_ipv6_tcp(tcp_pkt);
            free_buffer(gs1_data.sdu);
            break;
        }
        default: {
            break;
        }
    }


    return LD_OK;
}

void *exec_gsg(void *args) {
    net_element_t *net_ele = args;
    if (!net_ele)   return NULL;
    net_ele->inline_element = init_gsg_entity();
    if (init_element_service(net_ele, gsg_server_handler, gsg_client_handler) != LD_OK) {
        return NULL;
    }

    if (direct_snp) {
        while (1) {
            uint8_t connected_peer = 0;
            FOREACH_PEERS(net_ele->server_interfaces, {
                if (peer->is_connect == TRUE) {
                    connected_peer++;
                }
                });

            if (connected_peer == net_ele->server_interface_count) break;
        }

        if (memcmp((char *)net_ele->element_tag, "GSG_010", 7) == 0) {
            if (init_gsg_as_entities(net_ele) != LD_OK) {
                log_error("Cannot init 40 air stations");
                return NULL;
            }
        }

        usleep(10000);
    }

    cn_log_info(net_ele->element_tag, INTERFACE_UNDEFINED, "exec finished");

    return NULL;
}

l_err start_gsg(net_element_t *net_element) {
    cn_log_info(net_element->element_tag, INTERFACE_UNDEFINED, "start");
    pthread_create(&net_element->th, NULL, exec_gsg, net_element);
    pthread_detach(net_element->th);
    return LD_OK;
}

l_err stop_gsg(net_element_t *net_ele) {
    cn_log_error(net_ele->element_tag, INTERFACE_UNDEFINED, "stop");
    if (net_ele->inline_element) {
        free_gsg_entity(net_ele->inline_element);
    }
    return LD_OK;
}
